package com.ifonly.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author <a href="mailto:ifonlymaster@163.com">ifonly</a>
 * @version 1.0 2015-12-11 13:48
 * @since JDK 1.6
 */
public class ReflectUtils {

    /**
     * 某个类是否有指定方法
     *
     * @param clazz          需要验证的类
     * @param methodName     方法名
     * @param parameterTypes 参数类型列表
     * @return true - 有指定方法
     */
    public static boolean hasMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
        try {
            Method method = clazz.getMethod(methodName, parameterTypes);
            return method != null;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    public static Method[] publicMethods(Class<?> clazz, boolean isDeclared) {
        Method[] methods;
        if (isDeclared) {
            methods = clazz.getDeclaredMethods();
        } else {
            methods = clazz.getMethods();
        }

        List<Method> results = new ArrayList<Method>();

        if (methods != null && methods.length > 0) {
            for (Method method : methods) {
                if (Modifier.isPublic(method.getModifiers())) {
                    results.add(method);
                }
            }
            return results.toArray(new Method[results.size()]);
        }

        return new Method[0];
    }

    public static Map<String, Object> annotationInvoke(Annotation annotation) {
        try {
            Method[] methods = annotation.annotationType().getDeclaredMethods();
            Map<String, Object> map = new HashMap<String, Object>();
            for (Method method : methods) {
                String methodName = method.getName();
                Object result = method.invoke(annotation);
                map.put(methodName, result);
            }
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Object annotationInvoke(Annotation annotation, String methodName) {
        try {
            Method method = annotation.annotationType().getMethod(methodName);
            return method.invoke(annotation);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Object methodInvoke(Object target, Method method, Object...args)
            throws InvocationTargetException, IllegalAccessException {
        return method.invoke(target, args);
    }

    public static <T> T newInstance(Class<T> clazz) {
        try {
            return clazz.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public static Object newInstance(String className) {
        try {
            Class<?> clazz = Class.forName(className);
            return clazz.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    public static Field getDeclaredField(Class<?> clazz, String name) {
        try {
            return clazz.getDeclaredField(name);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }

}
